using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Services;
using MainGame.StateManagement;

namespace MainGame.GamePlay
{
  using PartialScores = MainGame.StateManagement.PartialScores;

  /// <summary>
  /// Gestiamo le regole di gioco, l'inizio della partita,
  /// le condizioni di fine partita e gli assegnamenti di punteggio
  /// </summary>
  public class GamePlayLayer : PlayerLayer
  {
    public GamePlayLayer(Game game)
      : base(game)
    {
      UpdateOrder = (int)ComponentOrders.LOGIC;
    }

    protected override void OnTurnChanged()
    {
      if (blocks.Count == NUM_PLAYERS)
      {
        if (blocks.All(b => b.Cards.Any()))
        {
          var reference_color = blocks[0].Cards.First().Color;
          var loser = blocks.Where(b => b.Cards.First().Color == reference_color)
                            .MaxBy(b => b.Cards.First().Value);
          loser.PlayedBy.Score += NUM_PLAYERS;
          blocks.Clear();
        }
      }

      base.OnTurnChanged();
    }

    protected override void BoardManager_ClickPlayerCard(int player_index, int card_index)
    {
        base.BoardManager_ClickPlayerCard(player_index, card_index);
    }

    protected override void BoardManager_ReleasePlayerCard(int player_index, int card_index)
    {
        Card a, b;
        if (card_index > 0 && card_index < (players[player_index].Cards.Count() - 1))
        {
            a = players[player_index].Cards[card_index - 1];
            b = players[player_index].Cards[card_index + 1];
            if (CheckCards(a, b))
            {
                ++players[player_index].Score;
                players[player_index].Cards[card_index].Selected = false;
                players[player_index].Cards.RemoveAt(card_index - 1);
            }
        }

        // Condizione di Fine Partita (Vittoria)
        // Carte sul tavolo = 2 e Carte del Mazzo = 0
        if (players[player_index].Cards.Count() == 2 && Pack.Cards.Count==0)
        {
            score.PlayerScores = (from p in players
                                  select new PlayerScore()
                                  {
                                      Name = p.Name,
                                      Score = p.Score
                                  }).ToList();
            SavePartialScore(score);
            LevelWon(score);
        }

        // To Do 
        // Inserire condizione di Sconfitta-Stallo (Non ci sono mosse possibili)

        base.BoardManager_ReleasePlayerCard(player_index, card_index);
    }

    protected override void StartGame()
    {
      var range = (from i in Enumerable.Range(1, 13) select i);
      Func<CardColor, IEnumerable<Card>> colors = c =>
        from i in range select new Card() { Color = c, Value = i, Selected = false };
      
      // Crea un nuovo mazzo
      pack = new GamePlay.Pack()
      {
        Cards = colors(CardColor.Blue).Concat(
             colors(CardColor.Green)).Concat(
             colors(CardColor.Red)).Concat(
             colors(CardColor.White)).ToList()
      };
      
      // Mischia il mazzo
      var r = new Random();
      for (int i = 0; i < pack.Cards.Count / 2; i++)
      {
        var ai = r.Next(pack.Cards.Count);
        var bi = r.Next(pack.Cards.Count);

        var a = pack.Cards[ai];
        var b = pack.Cards[bi];

        pack.Cards[bi] = a;
        pack.Cards[ai] = b;
      }

      // Crea i giocatori
      for (int p = 0; p < NUM_PLAYERS; p++)
        players.Add(new Player()
        {
          Score = 0,
          Hand = new PlayerBlock() { Cards = new List<Card>() },
          IsHuman = false,
          Name = Locale.Strings.Player + " " + p.ToString() //"Player " + p.ToString()
        });
#warning PER ATTIVARE UN GIOCATORE UMANO, VEDERE QUI
      players[0].IsHuman = true;
      players[0].Name = "Giuseppe";

      // Assegna le carte
      for (int i = 0; i < STARTING_CARDS; i++)
      {
        for (int p = 0; p < NUM_PLAYERS; p++)
        {
          pick_player(p);
        }
      }

      //CurrentPlayerIndex = r.Next(NUM_PLAYERS);
      CurrentPlayerIndex = 0;
    }

    /// <summary>
    /// Assegna una carta a un giocatore
    /// </summary>
    /// <param name="index">L'indice del giocatore nell'array dei giocatori</param>
    void pick_player(int index)
    {
      if (pack.Cards.Count > 0)
      {
        players[index].Cards.Add(pack.Cards.First());
        pack.Cards = pack.Cards.Skip(1).ToList();
      }
    }

    /// <summary>
    /// Controlla se due carte hanno lo stesso seme o lo stesso valore
    /// </summary>
    /// <param name="a">La prima carta</param>
    /// <param name="b">La seconda carta</param>
    /// <returns></returns>
    public bool CheckCards(Card a, Card b)
    {
      if (a != null && b != null)
      {
        if (a.Color.Equals(b.Color))
          return true;
        if (a.Value.Equals(b.Value))
          return true;
      }
      return false;
    }

    /// <summary>
    /// Salva il punteggio di tutti i giocatori per il round corrente
    /// </summary>
    /// <param name="score">I punteggi da salvare</param>
    protected void SavePartialScore(Score score)
    {
      if (PartialScores.scoreList == null)
        PartialScores.scoreList = new List<Score>();
      PartialScores.scoreList.Add(score);
    }
  }
}
